
-- Internalisation
local next, type, select, pcall = next, type, select, pcall
local randomseed, random, huge = math.randomseed, math.random, math.huge
local floor, max, min = math.floor, math.max, math.min

----
local tonumber = tonumber
local tostring = tostring

local string_sub = string.sub
local string_find = string.find

local re_find = ngx.re.find

local _ = {_VERSION = '0.09'}



-- f(key, value) at each step of iteration.
-- <br/><em>Aliased as `forEach`</em>.
-- @name each
-- @tparam table t a table
-- @tparam function f an iterator function, prototyped as `f(key, value, ...)`
-- @tparam[opt] vararg ... Optional extra-args to be passed to function `f`
-- @see eachi
function _.each(t, f, ...)
  re_find = f
  
  if _.empty(t) then
     f ("val is  empty")
  else

    for index,value in pairs(t) do
      if _.isTable(value) then
        _.each(value, f, ...)
      else
        f(index .."\t",value,...)
      end
      
    end
  end  
end

-- @name eachi
-- @tparam table t a table
-- @tparam function f an iterator function, prototyped as `f(key, value, ...)`
-- @tparam[opt] vararg ... Optional extra-args to be passed to function `f`
-- @see each
function _.eachi(t, f, ...)
  local lkeys = _.sort(_.select(_.keys(t), function(k,v)
    return _.isInteger(v)
  end))
  for k, key in ipairs(lkeys) do
    f(key, t[key],...)
  end
end


-- 将一个一维数组的值转化为字符串 
-- {'lastname', 'email', 'phone'} =>lastname,email,phone
-- @glue 默认为空的字符串。 
-- @pieces 你想要转换的数组。
-- @return string
function _.implode ( glue , pieces )
  
  local glue = glue or ' '

  if _.isEmpty(pieces) then return '' end
  if not _.isTable(pieces) then return '' end

  local re_str = ''
  local len = #pieces
  
  for k,val in ipairs(pieces) do

  	re_str = re_str .. val
  	if k ~= len then
  	   re_str = re_str .. glue
  	end
     
  end

  return re_str
end

-- 使用一个字符串分割另一个字符串
-- 此函数返回由字符串组成的数组，每个元素都是 string的一个子串，它们被字符串 delimiter作为边界点分割出来。
-- @delimiter 边界上的分隔字符。 
-- @string 输入的字符串。 
-- @limit int 如果设置了 limit参数并且是正数，则返回的数组包含最多 limit个元素，而最后那个元素将包含 string的剩余部分。 
-- @treturn {}
function _.explode (delimiter , string ,limit )
	
	local limit = tonumber(limit)

	local nFindStartIndex = 1 	--开始搜索 
    local nSplitIndex = 1 

    local arr = {}

    while true do  
       local lastIndex = string_find(string, delimiter, nFindStartIndex)

       if not lastIndex then  
        arr[nSplitIndex] = string_sub(string, nFindStartIndex, #string)
        break
       end

       
       if  limit and nSplitIndex >= limit  then
       	arr[nSplitIndex] = string_sub(string, nFindStartIndex)
       	break
       else
       	arr[nSplitIndex] = string_sub(string, nFindStartIndex, lastIndex - 1)
       	nFindStartIndex = lastIndex + #delimiter  
       	nSplitIndex = nSplitIndex + 1
       end
    end

    return arr  
end

function _.ltrim_ngx(res) 

	if _.isEmpty(res) then return '' end

 
    local from, to, err = re_find(res, [[^\s+]], "jo")


    if from then
	    res = string_sub(res, to+1)
 	end

    return res  
end 

function _.rtrim_ngx(res) 

	if _.isEmpty(res) then return '' end

    local from, to, err = re_find(res, [[\s*$]], "jo")

    if from then
	    res = string_sub(res, 1, from-1)
 	end


    return res  
end 

function _.trim_ngx(res)  
	if _.isEmpty(res) then return '' end

    local res1 = _.ltrim_ngx(res)  
    local res2 = _.rtrim_ngx(res1)  
    return res2  
end  


function _.ltrim(s)  
    if _.isEmpty(s) then return '' end

    local res = s  
    local tmp = string_find(res, '%S')  
    if not tmp then  
        res = ''  
    elseif tmp ~= 1 then  
        res = string_sub(res, tmp)  
    end  
    return res  
end  

function _.rtrim(s)  
	if _.isEmpty(s) then return '' end

    local res = s  
    local tmp = string_find(res, '%S%s*$')  
    if not tmp then  
        res = ''  
    elseif tmp ~= #res then  
        res = string_sub(res, 1, tmp)  
    end  
  
    return res  
end  
  
function _.trim(s)  
	if _.isEmpty(s) then return '' end

    local res1 = _.ltrim(s)  
    local res2 = _.rtrim(res1)  
    return res2  
end  


function _.get_timestamp()
    return os.date('%Y%m%d%H%M%S', ngx.time())
end

function _.get_timestamp2()
    return os.date('%Y-%m-%d %H:%M:%S', ngx.time())
end

-- Checks if the given arg is a table.
-- @name isTable
-- @tparam table t a value to be tested
-- @treturn boolean `true` or `false`
function _.isTable(t)
  return type(t) == 'table'
end

-- Checks if the given argument is an array. Assumes `obj` is an array
-- if is a table with integer numbers starting at 1.
-- @name isArray
-- @tparam table obj an object
-- @treturn boolean `true` or `false`
function _.isArray(obj)
  if not _.isTable(obj) then return false end
  -- Thanks @Wojak and @Enrique García Cota for suggesting this
  -- See : http://love2d.org/forums/viewtopic.php?f=3&t=77255&start=40#p163624
  local i = 0
  for __ in pairs(obj) do
     i = i + 1
     if _.isNil(obj[i]) then return false end
  end
  return true
end

-- 如果 var 是非空或非零的值，则 empty() 返回 FALSE。换句话说，
-- ""、0、NULL、FALSE、array()、var $var;以及没有任何属性的对象都将被认为是空的，
-- 如果 var 为空，则返回 TRUE。 
-- @name isEmpty
-- @tparam[opt] table|string obj an object
-- @treturn boolean `true` or `false`
function _.empty(obj)
  if obj == false or obj == ngx.null then return true end

  if _.isNil(obj) then return true end
  if _.isString(obj) then return #obj==0 end

  if _.isNumber(obj) and obj ~=0 then return false end

  if _.isTable(obj) then return next(obj)==nil end

  return false
end

function _.isEmpty(obj)
  return _.empty(obj)
end

-- Checks if the given argument is a *string*.
-- @name isString
-- @tparam table obj an object
-- @treturn boolean `true` or `false`
function _.isString(obj)
  return type(obj) == 'string'
end

-- Checks if the given argument is a function.
-- @name isFunction
-- @tparam table obj an object
-- @treturn boolean `true` or `false`
function _.isFunction(obj)
   return type(obj) == 'function'
end

-- Checks if the given argument is nil.
-- @name isNil
-- @tparam table obj an object
-- @treturn boolean `true` or `false`
function _.isNil(obj)
  return obj==nil
end

-- Checks if the given argument is a number.
-- @name isNumber
-- @tparam table obj a number
-- @treturn boolean `true` or `false`
-- @see isNaN
function _.isNumber(obj)
  return type(obj) == 'number'
end

-- Checks if the given argument is NaN see http://en.wikipedia.org/wiki/NaN
-- @name isNaN
-- @tparam table obj a number
-- @treturn boolean `true` or `false`
-- @see isNumber
function _.isNaN(obj)
  return _.isNumber(obj) and obj~=obj
end

-- Checks if the given argument is a finite number.
-- @name isFinite
-- @tparam table obj a number
-- @treturn boolean `true` or `false`
function _.isFinite(obj)
  if not _.isNumber(obj) then return false end
  return obj > -huge and obj < huge
end


-- Checks if the given argument is a boolean.
-- @name isBoolean
-- @tparam table obj a boolean
-- @treturn boolean `true` or `false`
function _.isBoolean(obj)
  return type(obj) == 'boolean'
end

-- Checks if the given argument is an integer.
-- @name isInteger
-- @tparam table obj a number
-- @treturn boolean `true` or `false`
function _.isInteger(obj)
  return _.isNumber(obj) and floor(obj)==obj
end

-- next 指令是不能被 LuaJIT 的 JIT 编译优化，并且 LuaJIT 貌似没有明确计划支持这个指令优化，在不是必须的情况下，尽量少用。
function _.isTableEmpty(t)
    if t == nil or next(t) == nil then
        return true
    else
        return false
    end
end

return _